package com.tyjt.vehfinder.core.actor;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.pattern.Patterns;
import akka.util.Timeout;
import cn.hutool.extra.spring.SpringUtil;
import com.tyjt.vehfinder.core.akka.CreateActorMsg;
import com.tyjt.vehfinder.core.akka.SpringExtProvider;
import com.tyjt.vehfinder.core.akka.Supervisor;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 所有的车辆管理器
 */
@Component
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Data
@Slf4j
public class VehMgr implements InitializingBean, ApplicationRunner {
    private static VehMgr instance;

    public static VehMgr getInstance() {
        return instance;
    }


    @Resource
    private ActorSystem actorSystem;

    private ActorRef supervisor;
    //  所有的vehId - actorRef
    public Map<String, ActorRef> vehMap = new ConcurrentHashMap<>();

    public Map<String, ActorRef> trackingActorMap = new ConcurrentHashMap<>();


    private Set<String> penddingSet = new HashSet<>();

    private Set<String> trackingPenddingSet = new HashSet<>();

    ScheduledExecutorService scheduledExecutorService;

    @Override
    public synchronized void afterPropertiesSet() {
        instance = this;
    }

    private ActorRef createVehActor(String vehId) {
        Props props = SpringExtProvider.getInstance().get(actorSystem).create(VehActor.class.getSimpleName());
        Timeout timeout = new Timeout(Duration.create(2, TimeUnit.SECONDS));
        Future<Object> future = Patterns.ask(supervisor, new CreateActorMsg(props, vehId), timeout);
        try {
            ActorRef ref = (ActorRef) Await.result(future, timeout.duration());
            log.info("create actor success {}  uid {} ", ref.path(), ref.path().uid());
            vehMap.put(vehId, ref);
            return ref;
        } catch (Exception e) {
            log.error("", e);
            penddingSet.remove(vehId);
        }
        return null;
    }


    public void sendMsg2Veh(String vehId, Object msg) {
        if (penddingSet.contains(vehId)) {
            log.info("creating  vehId {} ", vehId);
            return;
        }
        ActorRef actorRef = vehMap.get(vehId);
        if (actorRef == null) {
            penddingSet.add(vehId);
            actorRef = createVehActor(vehId);
            if (actorRef == null) {
                log.error("create fail  vehId {}", vehId);
                return;
            }
            penddingSet.remove(vehId);
        }
        actorRef.tell(msg, ActorRef.noSender());
    }


    public void stopActor(String vehId) {
        ActorRef actorRef = vehMap.get(vehId);
        if (actorRef != null) {
            SpringUtil.getBean(ActorSystem.class).stop(actorRef);
        }
        //  清理缓存
        vehMap.remove(vehId);
    }

    @Override
    public void run(ApplicationArguments args) {
        //  启动监督者
        supervisor = actorSystem.actorOf(Props.create(Supervisor.class), "supervisor");
    }


}
